#include <allegro5\allegro.h>
#include <allegro5\allegro_primitives.h>
#include <allegro5\allegro_image.h>
#include <allegro5\allegro_font.h>
#include <allegro5\allegro_ttf.h>

#include <math.h>
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

//#include "Camera.h"
#include "Structs.h"
#include "Allegro_Misc.h"
#include "camera.h"
#include "Map_Loader.h"

//Global Constants
const int MAX_FPS = 60;

ALLEGRO_BITMAP* image = NULL;
ALLEGRO_FONT* font;

imageArray base;
imageArray fringe;
imageArray objects;
bitmapImage notWalkable;

bool pressedKeys[ALLEGRO_KEY_MAX];
bool mouseClick[3] = {false, false, false};

Point dragXY;
short int mouseWheel = 0;
short int tileType = 0;

void drawMap(mapCell*** &map, Camera camera, MapInfo* info);

int WINDOW_WIDTH;
int WINDOW_HEIGHT;

bool team = false;

int main() {

	WINDOW_WIDTH = 800;
	WINDOW_HEIGHT = 600;

	bool done = false;
	bool redraw = true;

	//allegro variable
	ALLEGRO_DISPLAY *display = NULL;
	ALLEGRO_EVENT_QUEUE *event_queue = NULL;
	ALLEGRO_TIMER *timer = NULL;
	mapCell*** map;
	MapInfo* info = new MapInfo;

	map = loadMap(info);

	allegroInit(WINDOW_WIDTH, WINDOW_HEIGHT, MAX_FPS, display, event_queue, timer);
	font = al_load_ttf_font("rsc/Font/8bitlim.ttf", 18 , 0);
	
	ALLEGRO_MONITOR_INFO* infoM = new ALLEGRO_MONITOR_INFO;
	al_get_monitor_info(0, infoM);
	WINDOW_WIDTH = infoM->x2 - 128;
	WINDOW_HEIGHT = infoM->y2 - 128;

	loadImages(base, fringe, objects, &notWalkable);

	Camera camera(WINDOW_WIDTH, WINDOW_HEIGHT, info->tileSize, info->numTilesX, info->numTilesY);

	for(int i = 0; i < ALLEGRO_KEY_MAX; i++)
		pressedKeys[i] = false;

	al_start_timer(timer);

	ALLEGRO_MOUSE_STATE state;

	int ti, tj;
	int size;
	double dX, dY;

	while(!done) {
		ALLEGRO_EVENT ev;
		al_wait_for_event(event_queue, &ev);

		switch(ev.type) {

		case ALLEGRO_EVENT_DISPLAY_CLOSE:
			done = true;
			break;

		case ALLEGRO_EVENT_TIMER:
			al_get_mouse_state(&state);

			if(pressedKeys[ALLEGRO_KEY_DOWN] == true)
				camera.addToY(2.5);
			if(pressedKeys[ALLEGRO_KEY_UP] == true)
				camera.addToY(-2.5);
			if(pressedKeys[ALLEGRO_KEY_LEFT] == true)
				camera.addToX(-2.5);
			if(pressedKeys[ALLEGRO_KEY_RIGHT] == true)
				camera.addToX(2.5);

			if(mouseClick[1] == true) {
				dX = al_get_mouse_state_axis(&state, 0);
				dX = dragXY.x - dX;
				dY = al_get_mouse_state_axis(&state, 1);
				dY = dragXY.y - dY;

				camera.addToX(dX);
				camera.addToY(dY);

				dragXY.x = state.x;
				dragXY.y = state.y;
			} 

			if(mouseClick[0] == true) {
				ti = floor((state.x + camera.getXY().x)/info->tileSize);
				tj = floor((state.y + camera.getXY().y)/info->tileSize);
				if(ti >= 0 && ti < info->numTilesX)
					if(tj >= 0 && tj < info->numTilesY)
						if(tileType == 0)
							map[ti][tj]->base = mouseWheel;
						else if(tileType == 1) {
							map[ti][tj]->fringe = mouseWheel;
						}
						else if(tileType == 2) {
							map[ti][tj]->object = mouseWheel;
						}
						else if(tileType == 4) {
							if(mouseWheel == 0)
								map[ti][tj]->walkable = false;
							else if(mouseWheel == 1)
								map[ti][tj]->walkable = true;
						}
						else if(tileType == 5) {
							map[ti][tj]->cost = mouseWheel;
						}
						else if(tileType == 6) {
							map[ti][tj]->entity = mouseWheel + 1;
							map[ti][tj]->team = team;
						}
			}

			if(mouseClick[2] == true) {
				ti = floor((state.x + camera.getXY().x)/info->tileSize);
				tj = floor((state.y + camera.getXY().y)/info->tileSize);

				if(tileType == 0)
					map[ti][tj]->base = -1;
				else if(tileType == 1)
					map[ti][tj]->fringe = -1;
				else if(tileType == 2)
					map[ti][tj]->object = -1;
				else if(tileType == 6)
					map[ti][tj]->entity = 0;
			}

			redraw = true;
			break;

		case ALLEGRO_EVENT_KEY_DOWN:
			if(ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
				pressedKeys[ALLEGRO_KEY_DOWN] = true;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
				pressedKeys[ALLEGRO_KEY_UP] = true;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
				pressedKeys[ALLEGRO_KEY_LEFT] = true;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
				pressedKeys[ALLEGRO_KEY_RIGHT] = true;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_B) {
				tileType = 0;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_F){
				tileType = 1;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_O){
				tileType = 2;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_W){
				tileType = 4;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_C){
				tileType = 5;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_E){
				tileType = 6;
				mouseWheel = 0;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_T){
				if(team)
					team = false;
				else
					team = true;
			}
			else if(ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
				done = true;
			break;

		case ALLEGRO_EVENT_KEY_UP:
			if(ev.keyboard.keycode == ALLEGRO_KEY_DOWN)
				pressedKeys[ALLEGRO_KEY_DOWN] = false;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_UP)
				pressedKeys[ALLEGRO_KEY_UP] = false;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_LEFT)
				pressedKeys[ALLEGRO_KEY_LEFT] = false;
			else if(ev.keyboard.keycode == ALLEGRO_KEY_RIGHT)
				pressedKeys[ALLEGRO_KEY_RIGHT] = false;
			break;

		case ALLEGRO_EVENT_MOUSE_AXES:
			if(tileType == 0)
				size = base.arraySize;
			else if(tileType == 1)
				size = fringe.arraySize;
			else if(tileType == 2)
				size = objects.arraySize;
			else if(tileType == 4)
				size = 2;
			else if(tileType == 5)
				size = 10;
			else if(tileType == 6)
				size = 2;

			if(ev.mouse.z > 0) {
				mouseWheel++;
				if(mouseWheel >= size)
					mouseWheel = 0;
			}
			else if(ev.mouse.z < 0) {
				mouseWheel--;
				if(mouseWheel < 0)
					mouseWheel = size - 1;
			}
			al_set_mouse_z(0);
			break;

		case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
			if(ev.mouse.button == 1) 
				mouseClick[0] = true;
			if(ev.mouse.button == 2) {
				mouseClick[1] = true;
				dragXY.x = ev.mouse.x;
				dragXY.y = ev.mouse.y;
			}
			if(ev.mouse.button == 3)
				mouseClick[2] = true;
			break;

		case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
			if(ev.mouse.button == 1)
				mouseClick[0] = false;
			if(ev.mouse.button == 2)
				mouseClick[1] = false;
			if(ev.mouse.button == 3) 
				mouseClick[2] = false;
			break;

		}
		if(redraw && al_is_event_queue_empty(event_queue))
		{
			redraw = false;
			drawMap(map, camera, info);

			al_flip_display();
			al_clear_to_color(al_map_rgb(0,0,0));
		}
	}

	al_destroy_display(display);
	al_destroy_bitmap(image);

	saveMap(map, info);

	ALLEGRO_BITMAP* out = al_create_bitmap(100*32, 100*32);
	al_set_target_bitmap(out);

	for(int i = 0; i < 100; i++) {
		for(int j = 0; j < 100; j++) {
			mapCell* tile = map[i][j];

			if(tile->base >= 0) 
				al_draw_bitmap(base.images[tile->base].image, (info->tileSize * i), (info->tileSize * j), 0);
			//if(i == 50 || j == 50)
				//al_draw_circle((info->tileSize * i), (info->tileSize * j), 3, al_map_rgb(0, 0, 255), 3);
		}
	}
	for(int j = 0; j < 100; j++) {
		for(int i = 0; i < 100; i++) {
			mapCell* tile = map[i][j];
			if(tile->fringe >= 0) {
				al_draw_bitmap(fringe.images[tile->fringe].image, 
				(info->tileSize * i), 
				(info->tileSize * j), 0);
				//al_draw_circle((info->tileSize * i), (info->tileSize * j), 5, al_map_rgb(0,0,0), 5);
			}
		}
	}

	for(int j = 0; j < 100; j++) {
		for(int i = 0; i < 100; i++) {
			mapCell* tile = map[i][j];
			if(tile->object >= 0) {
				al_draw_bitmap(objects.images[tile->object].image, 
				(info->tileSize * i), 
				(info->tileSize * j), 0);
				//al_draw_circle((info->tileSize * i), (info->tileSize * j), 2, al_map_rgb(0,255,0), 1);
			}
		}
	}

	al_save_bitmap("Map.png", out);
	al_destroy_bitmap(out);

	for(int i = 0; i < base.arraySize; i++)
		al_destroy_bitmap(base.images[i].image);

	for(int i = 0; i < fringe.arraySize; i++)
		al_destroy_bitmap(fringe.images[i].image);

	delete base.images;
	delete fringe.images;

	for(int i = 0; i < info->numTilesX; i++) {
		for(int j = 0; j < info->numTilesY; j++) {
			delete map[i][j];
		}
		delete map[i];
	}
	delete map;

	return 0;
}

void drawMap(mapCell*** &map, Camera camera, MapInfo* info) {
	ALLEGRO_MOUSE_STATE state;
	al_get_mouse_state(&state);

	Point camPos = camera.getXY();

	int startI = floor(camPos.x / info->tileSize);
	int startJ = floor(camPos.y / info->tileSize);

	if(startI > 2)
		startI -= 3;
	if(startJ > 2)
		startJ -= 3;

	int endI = ceil((camPos.x + WINDOW_WIDTH) / info->tileSize);
	int endJ = ceil((camPos.y + WINDOW_HEIGHT) / info->tileSize);

	for(int i = startI; i < endI; i++) {
		for(int j = startJ; j < endJ; j++) {
			mapCell* tile = map[i][j];

			if(tile->base >= 0) 
				al_draw_bitmap(base.images[tile->base].image, (info->tileSize * i) - camPos.x, (info->tileSize * j) - camPos.y, 0);
			if(i == 50 || j == 50)
				al_draw_circle((info->tileSize * i) - camPos.x, (info->tileSize * j) - camPos.y, 3, al_map_rgb(0, 0, 255), 3);
		}
	}
	for(int j = startJ; j < endJ; j++) {
		for(int i = startI; i < endI; i++) {
			mapCell* tile = map[i][j];
			if(tile->fringe >= 0) {
				al_draw_bitmap(fringe.images[tile->fringe].image, 
				(info->tileSize * i) - camPos.x, 
				(info->tileSize * j) - camPos.y, 0);
				al_draw_circle((info->tileSize * i) - camPos.x, (info->tileSize * j) - camPos.y, 5, al_map_rgb(0,0,0), 5);
			}
		}
	}

	stringstream st;
	string s;

	for(int j = startJ; j < endJ; j++) {
		for(int i = startI; i < endI; i++) {
			mapCell* tile = map[i][j];
			if(tile->object >= 0) {
				al_draw_bitmap(objects.images[tile->object].image, 
				(info->tileSize * i) - camPos.x, 
				(info->tileSize * j) - camPos.y, 0);
				al_draw_circle((info->tileSize * i) - camPos.x, (info->tileSize * j) - camPos.y, 2, al_map_rgb(0,255,0), 8);
				if(tile->object == 10)
					cout << (info->tileSize * i) << " " << (info->tileSize * j) << endl;
			}
			if(tileType == 4)
				if(!tile->walkable)
					al_draw_bitmap(notWalkable.image, (info->tileSize * i) - camPos.x, (info->tileSize * j) - camPos.y, 0);
			if(tileType == 5) {
				st << tile->cost;
				s = st.str();
				st.str("");
				al_draw_text(font, al_map_rgb(0, 0, 0), 32*i - camPos.x, 32*j - camPos.y, 0, s.c_str());
			}
			if(tile->entity > 0) {
				string c = "S";
				if(tile->entity == 2)
					c = "A";
				if(tile->team) {
					al_draw_text(font, al_map_rgb(0, 255, 0), 32*i - camPos.x, 32*j - camPos.y, 0, c.c_str());
				}
				else {
					al_draw_text(font, al_map_rgb(0, 0, 255), 32*i - camPos.x, 32*j - camPos.y, 0, c.c_str());
				}
			}
		}
	}

	al_draw_rectangle(5*32 - camPos.x, 26*32 - camPos.y, 15*32 - camPos.x, 34*32 - camPos.y, al_map_rgb(255, 0, 0), 5);

	Point p;
	p.x = (state.x / 32) * 32;
	p.y = (state.y / 32) * 32;

	if(tileType == 0)
		al_draw_bitmap(base.images[mouseWheel].image, state.x - info->tileSize/2, state.y - info->tileSize/2, 0);
	else if(tileType == 1)
		al_draw_bitmap(fringe.images[mouseWheel].image, p.x, p.y, 0);
	else if(tileType == 2)
		al_draw_bitmap(objects.images[mouseWheel].image, p.x, p.y, 0);
	else if(tileType == 4) {
		if(mouseWheel == 0)
			al_draw_bitmap(notWalkable.image, state.x - info->tileSize/2, state.y - info->tileSize/2, 0);
	}
	else if(tileType == 5) {
		st << mouseWheel;
		s = st.str();
		st.str("");
		al_draw_text(font, al_map_rgb(0, 0, 0), p.x, p.y, 0, s.c_str());
	}
	else if(tileType == 6) {
		if(tileType == 6) {
				string c = "S";
				if(mouseWheel == 1)
					c = "A";
				if(team) {
					al_draw_text(font, al_map_rgb(0, 255, 0), p.x, p.y, 0, c.c_str());
				}
				else {
					al_draw_text(font, al_map_rgb(0, 0, 255), p.x, p.y, 0, c.c_str());
				}
			}
	}

	al_draw_text(font, al_map_rgb(0, 0, 0), 20, WINDOW_HEIGHT - 30, 0, "B - Base Tiles, F - Fringe Tiles, O - Objects, W - Walkable Toggle");
}